/**
 * #info
 *
 *@author   yuanzhy
 *@createTime   2019/04/15
 *@updateTime   2019/04/15
 *@description  人民币输入组件
 */
/**
 * #item
 *
 * @type        aty-input-money
 * @cn          金额输入框
 * @nameprop   label
 * @menu        表单
 * @stPlugin    true
 * @stContainer false
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'
import formItem from '../form-item/form-item.js'

const prefixCls = config.prefix + '-input-money'

const maxNum = 9999999999999.99
// module
const module = {
  name: config.prefix + '-input-money',
  // 混入
  mixins: [formItem],
  components: {},
  props: {
    /**
     * #property
     *
     * @name    elementId
     * @cn      input id
     * @group   基本属性
     * @type    string
     * @description HTML label元素的for属性 input元素的id属性
     */
    elementId: {
      type: String
    },
    /**
     * #property
     *
     * @name    value
     * @cn      值
     * @group   基本属性
     * @type    string,number
     * @description input-money组件的值
     */
    value: {
      type: [Number, String],
      default: ''
    },
    /**
     * #property
     *
     * @name    max
     * @cn      最大值
     * @group   验证
     * @type    number
     * @bind    must
     * @value   9999999999999.99
     * @description 数据项的数值最大值
     */
    max: {
      type: Number,
      default: maxNum,
      validator (value) {
        return value <= maxNum
      }
    },
    /**
     * #property
     *
     * @name    decimalDigit
     * @cn      小数位数
     * @group   显示
     * @type    number
     * @bind    must
     * @value   2
     * @description 小数点最大可输入的位数, 默认为2
     */
    decimalDigit: {
      type: Number,
      default: 2
    },
    /**
     * #property
     *
     * @name    thousandth
     * @cn      千分位模式
     * @group   显示
     * @type    boolean
     * @bind    must
     * @value  true
     * @description 金额是否已千分位模式展示
     */
    thousandth: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    showChinese
     * @cn      是否显示中文金额
     * @group   显示
     * @type    boolean
     * @bind    must
     * @value  true
     * @description 默认大写汉字, 如需小写可通过指定lower-chinese实现
     */
    showChinese: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    lowerChinese
     * @cn      小写中文金额
     * @group   显示
     * @type    boolean
     * @value  false
     * @description 小写中文金额
     */
    lowerChinese: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {}
  },
  // 监听值发生变化
  watch: {
    chineseValue (newVal) {
      /**
       * #event
       *
       * @name    chinese-change
       * @cn      中文金额变化
       * @param   chineseMoney 变化后中文金额
       * @body
       * @description 中文金额变化事件
       */
      this.$emit('chinese-change', newVal)
    }
  },
  // 计算属性
  computed: {
    inputListeners: function () {
      const _this = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 从父级添加所有的监听器
        this.$listeners,
        // 自定义监听器，或覆写一些监听器的行为
        {
          keydown: function (event) {
            const cursorPos = _this.markCaretPosition()
            const key = event.keyCode
            let value = _this.$refs.inputDisplay.value
            if (_this.getSelection() === value) {
              value = ''
            }
            // 判断无效字符start ----------------------------------------------
            let illegal = !(
              _this.isNumberKey(key) ||
                _this.isDirectionKey(key) || // 上下左右
                (_this.thousandth && key === 188) || // 逗号
                _this.isPointKey(key) || // 点
                  // || this.isMinusKey(key) // 减号
                  key === 13 || // enter
                _this.isDeleteKey(key) ||
                _this.isCVKey(key)
            ) ||
                event.shiftKey || event.altKey || // || event.ctrlKey
                (_this.isPointKey(key) && (value === '' || value.includes('.'))) // 有小数点了不能再输入小数点
            // 光标在小数点后, 判断是否可输入
            if (illegal) {
              // 无效情况
            } else if (_this.isZeroKey(key)) {
              if (value.length && cursorPos === 0) { // 0不能在首位
                illegal = true
              } else if (value.startsWith('0') && (!value.includes('.') || cursorPos <= value.indexOf('.'))) { // 首位为0的情况, 也不能在小数点前输入0
                illegal = true
              } else if (value.includes('.') && _this.getDecimalDigit(value) === _this.decimalDigit) { // 小数点后不能超过小数位数
                illegal = true
              } else if (!value.includes('.')) {
                illegal = _this.exceedMaxValue(key)
              }
            } else if (_this.isDeletePoint(key, cursorPos) && value.includes('.') && !value.endsWith('.')) {
              illegal = true
            } else if (value.includes('.') && cursorPos >= value.indexOf('.') + 1) { // 小数情况
              if (!_this.isDeleteKey(key) && !_this.isDirectionKey(key) && _this.getDecimalDigit(value) === _this.decimalDigit) {
                illegal = true
              }
            } else {
              illegal = _this.exceedMaxValue(key)
            }
            // 判断无效字符 end ----------------------------------------------
            if (illegal) {
              if (event.preventDefault) {
                event.preventDefault()// 非IE浏览器
              } else { // IE浏览器
                event.returnValue = false
              }
            } else {
              _this.$emit('keydown', event)
            }
          },
          input: function (event) {
            let newValue = event.target.value
            _this.markCaretPosition()
            const decimalDigit = _this.getDecimalDigit(newValue)
            const hasIllegalChar = /[^\.\d,]/.test(newValue)
            const hasIllegalDecimal = decimalDigit > _this.decimalDigit
            if (hasIllegalChar) {
              newValue = newValue.replace(/[^\.\d,]/g, '')
            }
            if (hasIllegalDecimal) {
              newValue = newValue.substring(0, newValue.length - 1)
            }
            if (hasIllegalChar || hasIllegalDecimal) {
              _this.$refs.inputDisplay.value = newValue
              _this._caretPosition--
              _this.resetCaretPosition(_this.$refs.inputDisplay)
            } else if (newValue !== String(_this.value)) {
              _this.$emit('input', _this.getUpdateValue(newValue))
            }
          },
          blur: function (event) {
            _this.$emit('blur', event)
            _this.clearCaretPosition()
            _this.validate()
          }
        }
      )
    },
    // 外围class
    wrapClasses () {
      return [
        `${prefixCls}-wrapper`
      ].concat(this.formItemClasses)
    },
    wrapStyles () {
      return this.formItemStyles
    },
    // input的class
    inputClasses () {
      return [
        `${prefixCls}`,
        {
          [`${prefixCls}-disabled`]: this.$attrs.disabled !== undefined && this.$attrs.disabled !== false
        }
      ]
    },
    showValue: {
      // getter
      get: function () {
        return this.getShowValue(this.value)
      },
      // setter
      set: function (newValue) {
        this.$refs.inputDisplay.value = newValue
      }
    },
    // 转换后的值, 金额的汉字描述
    chineseValue () {
      let money = this.value
      // 汉字的数字
      const cnNums = this.lowerChinese ? ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九'] : ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
      // 基本单位
      const cnIntRadice = this.lowerChinese ? ['', '十', '百', '千'] : ['', '拾', '佰', '仟']
      // 对应整数部分扩展单位
      const cnIntUnits = ['', '万', '亿', '兆']
      // 对应小数部分单位
      const cnDecUnits = ['角', '分', '毫', '厘']
      /*
       * 整数金额时后面跟的字符
       * const cnInteger = '整';
       */
      const cnInteger = ''
      // 整型完以后的单位
      const cnIntLast = '元'
      // 金额整数部分
      let integerNum
      // 金额小数部分
      let decimalNum
      // 输出的中文金额字符串
      let chineseStr = ''
      // 分离金额后用的数组，预定义
      let parts
      if (!money) {
        return ''
      }
      // money = parseFloat(money);
      if (money > maxNum) {
        // 超出最大处理数字
        return ''
      }
      if (money == 0) {
        chineseStr = cnNums[0] + cnIntLast + cnInteger
        return chineseStr
      }
      // 转换为字符串
      money = money.toString()
      if (money.indexOf('.') === -1) {
        integerNum = money
        decimalNum = ''
      } else {
        parts = money.split('.')
        integerNum = parts[0]
        decimalNum = parts[1].substr(0, this.decimalDigit)
      }
      // 获取整型部分转换
      if (parseInt(integerNum, 10) > 0) {
        let zeroCount = 0
        const IntLen = integerNum.length
        for (let i = 0; i < IntLen; i++) {
          const n = integerNum.substr(i, 1)
          const p = IntLen - i - 1
          const q = p / 4
          const m = p % 4
          if (n == '0') {
            zeroCount++
          } else {
            if (zeroCount > 0) {
              chineseStr += cnNums[0]
            }
            // 归零
            zeroCount = 0
            chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
          }
          if (m == 0 && zeroCount < 4) {
            chineseStr += cnIntUnits[q]
          }
        }
        chineseStr += cnIntLast
      }
      // 小数部分
      if (decimalNum != '') {
        const decLen = decimalNum.length
        for (let i = 0; i < decLen; i++) {
          const n = decimalNum.substr(i, 1)
          if (n != '0') {
            chineseStr += cnNums[Number(n)] + cnDecUnits[i]
          }
        }
      }
      if (chineseStr == '') {
        chineseStr += cnNums[0] + cnIntLast + cnInteger
      } else if (decimalNum == '') {
        chineseStr += cnInteger
      }
      return chineseStr
    }
  },
  methods: {
    // 获得焦点
    focus () {
      // input 获得焦点
      this.$refs.inputDisplay.focus()
    },
    // 重置为初始值
    reset () {
      this.$refs.inputDisplay.value = this._originalValue
      this.showValue = this.getShowValue(this._originalValue)
      this.$emit('input', this._originalValue)
      this.$emit('change')
    },
    clearCaretPosition () {
      this._caretPosition = null
    },
    getShowValue (value) {
      this.resetCaretPosition()
      if (value === null || value === undefined || value === '') {
        return ''
      } else if (this.thousandth) {
        const _value = Artery.type(value) === 'string' ? Number(value) : value
        if (Number.isInteger(_value)) { // 是否为整数（Number 50，String 50.00）
          return _value.toString().replace(/\d(?=(\d{3})+$)/g, '$&,')
        } else {
          const point = _value.toString().split('.')[1].length
          let [sInt, sFloat] = _value.toFixed(point).split('.')
          sInt = sInt.replace(/\d(?=(\d{3})+$)/g, '$&,')
          return `${sInt}.${sFloat}`
        }
      } else {
        return value.toString()
      }
    },
    getUpdateValue (newValue) {
      this._oldValue = this.value
      // 赋值
      if (!newValue) {
        return null
      }
      if (Artery.type(newValue) === 'number') {
        return newValue
      }
      let v = newValue.replace(/[^\.\d]/g, '')
      if (v.indexOf('.') !== -1) {
        const decimalLen = v.split('.')[1].length
        if (decimalLen > this.decimalDigit) {
          v = v.substring(0, v.length - decimalLen + this.decimalDigit)
        }
      }
      return Number(v).valueOf() >= this.max ? Number(this.max) : Number(v)
    },
    exceedMaxValue (key) {
      // 整数或光标在整数
      if (this.max / this.value < 10) {
        // 不是一个数量级, 说明在输入的话就超标了
        const selection = this.getSelection()
        if (selection === ',' || selection.length === 0) {
          if (!this.isDeleteKey(key) && !this.isDirectionKey(key) && !this.isPointKey(key)) {
            return true
          }
        }
      }
      return false
    },
    markCaretPosition (obj = this.$refs.inputDisplay) {
      let result = 0
      if (obj.selectionStart >= 0) { // IE以外
        result = obj.selectionStart
      } else { // IE
        try {
          const rng = document.selection.createRange()
          rng.moveStart('character', -event.srcElement.value.length)
          result = rng.text.length
        } catch (e) {
          throw new Error(10, '无法获取光标位置')
        }
      }
      this._caretPosition = result
      return result
    },
    resetCaretPosition (tObj = this.$refs.inputDisplay) {
      if (!tObj || !this._caretPosition || !this.value) {
        return
      }
      let sPos = this._caretPosition
      if (sPos === tObj.value.length) { // 光标在最后, 不需要动态设置
        return
      }
      if (this.thousandth) {
        if (this._oldValue < this.value && this.value.toString().split('.')[0].replace(/,/g, '').length % 3 === 1) {
          sPos += 1 // 多了一个逗号的情况, pos需要加一个
        } else if (this._oldValue > this.value && this.value.toString().split('.')[0].replace(/,/g, '').length % 3 === 0) {
          sPos -= 1
        }
      }
      if (tObj.setSelectionRange) {
        setTimeout(function () {
          tObj.setSelectionRange(sPos, sPos)
          tObj.focus()
        }, 0)
      } else if (tObj.createTextRange) {
        const rng = tObj.createTextRange()
        rng.move('character', sPos)
        rng.select()
      }
    },
    getDecimalDigit (text) {
      text = text.toString()
      if (text.indexOf('.') === -1) {
        return 0
      } else {
        return text.split('.')[1].length
      }
    },
    isDirectionKey (key) {
      return key >= 37 && key <= 40
    },
    isNumberKey (key) {
      return (key >= 48 && key <= 57) || // 0-9
                (key >= 96 && key <= 105) // 小键盘0-9
    },
    isDeleteKey (key) {
      return key === 46 || key === 8 // delete backspace
    },
    isCVKey (key) {
      return event.ctrlKey && (key === 65 || key === 67 || key === 86 || key === 88) // ctrl+ a x c v
    },
    isPointKey (key) {
      return key === 190 || key === 110
    },
    isDeletePoint (key, cursorPos) {
      const value = this.$refs.inputDisplay.value
      if (key === 8 && cursorPos === value.indexOf('.') + 1) { // backspace
        return true
      } else if (key === 46 && cursorPos === value.indexOf('.')) { // delete
        return true
      }
      return false
    },
    isZeroKey (key) {
      return key === 48 || key === 96
    },
    isMinusKey (key) {
      return key === 189 || key === 109
    },
    getSelection () {
      return window.getSelection ? window.getSelection().toString() : document.selection.createRange().text
    }
  },
  updated () {
  },
  created () {
    // 保存初始值，用于reset
    this._originalValue = Artery.deepCopy(this.value)
    this._oldValue = this.value
  },
  mounted () {
  }
}
export default module
